package com.gzx.spring.boot.init;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import com.gzx.risk.core.init.ExtInit;
import com.gzx.spring.boot.utils.AopTargetUtils;

public class GzxInitHelper {
    private static Logger LOGGER = LoggerFactory.getLogger(GzxInitHelper.class);
    public static boolean TEST_INIT = false;

    public List<Object> findInitBeans(ApplicationContext ctx) throws Exception {
        List<Object> beans = new ArrayList<>();

        Map<String, Object> extInitMap = ctx.getBeansWithAnnotation(ExtInit.class);
        if (extInitMap != null && extInitMap.size() > 0) {
            for (String beanId : extInitMap.keySet()) {
                Object bean = extInitMap.get(beanId);
                Object realBean = AopTargetUtils.getTarget(bean);
                beans.add(realBean);
            }
        }

        return beans;
    }

    private void checkToInit(List<Object> allBeans, int order) {
        for (Object realBean : allBeans) {
            ExtInit tag = realBean.getClass().getAnnotation(ExtInit.class);
            if (tag != null && tag.order() == order) {
                try {
                    LOGGER.info("ExtInit for:{},order:{}", realBean.getClass().getName(), order);
                    checkToInitMethod(realBean);
                } catch (Exception e) {
                    LOGGER.error("ExtInit for:{} ERROR", realBean.getClass().getName(), e);
                }
            }
        }
    }

    private void checkToInitMethod(Object realBean) {
        Class<?> beanClass = realBean.getClass();
        while (true) {
            if (beanClass == Object.class) {
                break;
            }
            Method[] methods = beanClass.getDeclaredMethods();
            for (Method method : methods) {
                ExtInit tag = method.getAnnotation(ExtInit.class);
                if (tag != null) {
                    try {
                        method.invoke(realBean);
                    } catch (Exception e) {
                        Throwable logThrowable = e;
                        if (e.getCause() != null) {
                            logThrowable = e.getCause();
                        }
                        LOGGER.error("ERROR class:{},method:{}", realBean.getClass().getName(), method.getName(),
                                logThrowable);
                    }
                }
            }
            beanClass = beanClass.getSuperclass();
        }
    }

    public void extInit(ApplicationContext ctx) {
        try {
            if (TEST_INIT) {
                LOGGER.info("TestInit");
                return;
            } 
            List<Object> allBeans = findInitBeans(ctx);
            for (int i = 0; i <= 1000; i++) {
                checkToInit(allBeans, i);
            }
            LOGGER.info("extInit end.");
        } catch (Exception e) {
            LOGGER.error("extInit ERROR", e);
        }
    }
}
